#include <ptcPackParse.h>
static const uint8_t MCU_CONST_TYPE parseFixedHead[PTC_PACK_VER_PST] = {0X7A, 0XB5, 0X69}; // fixed head save
static void resetParseWork(struct ptcPackOption *parseIstc)
{
    parseIstc->parseState = protocolParseCommonStep_FixedHead;
    parseIstc->rcvCount = 0;
}

uint8_t ptcPackGetVersion(struct ptcPackOption *parseIstc)
{
    return parseIstc->pkptr[PTC_PACK_VER_PST];
}
int ptcPackSetVersion(struct ptcPackOption *parseIstc, uint8_t setCrypte)
{
    return (parseIstc->pkptr[PTC_PACK_VER_PST] = setCrypte);
}

ptcPackType ptcPackGetHeadSize(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        return PTC_PACK_V1_DATA_PST;
        break;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return 0;
}
uint16_t ptcPackGetDataSize(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        return convertOvtBigSysI16(ptr_value(uint16_t, &parseIstc->pkptr[PTC_PACK_V1_SIZE_PST]));
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return 0;
}
int ptcPackSetDataSize(struct ptcPackOption *parseIstc, uint16_t setsize)
{
    uint16_t tmpSize;
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        tmpSize = convertOvtBigSysI16(setsize);
        memcpy(&parseIstc->pkptr[PTC_PACK_V1_SIZE_PST], &tmpSize, sizeof(setsize));
        return setsize;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
const uint8_t *ptcPackGet485Addr(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        return &parseIstc->pkptr[PTC_PACK_V1_ADDR_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return NULL;
}
int ptcPackSet485Addr(struct ptcPackOption *parseIstc, const uint8_t *setAddr)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        memcpy(&parseIstc->pkptr[PTC_PACK_V1_ADDR_PST], setAddr, PTC_PACK_V1_ADDR_SIZE);
        return PTC_PACK_V1_ADDR_SIZE;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

int ptcPackCheckAddr(struct ptcPackOption *parseIstc, const uint8_t *myaddr)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        if(memcmp(&parseIstc->pkptr[PTC_PACK_V1_ADDR_PST], myaddr, PTC_PACK_V1_ADDR_SIZE) == 0)
        {
            return 0;
        }
        break;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

uint8_t ptcPackGetCrypte(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        return parseIstc->pkptr[PTC_PACK_V1_ENCYPT_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
int ptcPackSetCrypte(struct ptcPackOption *parseIstc, uint8_t setCrypte)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        parseIstc->pkptr[PTC_PACK_V1_ENCYPT_PST] = setCrypte;
        return 0;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

uint8_t *ptcPackGetUsrData(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        return &parseIstc->pkptr[PTC_PACK_V1_DATA_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return NULL;
}
int ptcPackSetUsrData(struct ptcPackOption *parseIstc, const uint8_t *usrData, ptcPackType dsize)
{
    if(parseIstc->pksize - ptcPackGetHeadSize(parseIstc) < dsize)
    {
        logerror("[psize=%d,ver=%d]dsize=%d", parseIstc->pksize, parseIstc->myVersion, dsize);
        return -1;
    }
    memcpy(ptcPackGetUsrData(parseIstc), usrData, dsize);
    ptcPackSetDataSize(parseIstc, dsize);
    return dsize;
}

uint8_t ptcPackGetCrcU8(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        return parseIstc->pkptr[PTC_PACK_V1_CRC_PST];
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
int ptcPackSetCrcU8(struct ptcPackOption *parseIstc, uint8_t setCrc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        parseIstc->pkptr[PTC_PACK_V1_CRC_PST] = setCrc;
        return 0;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}

ptcPackType ptcPackGetTotalSize(struct ptcPackOption *parseIstc)
{
    return ptcPackGetDataSize(parseIstc) + ptcPackGetHeadSize(parseIstc);
}
ptcPackType ptcPackGetRemainSize(struct ptcPackOption *parseIstc)
{
    return parseIstc->pksize - ptcPackGetHeadSize(parseIstc);
}

ptcPackType ptcPackFinishData(struct ptcPackOption *parseIstc)
{
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        ptcPackSetCrcU8(parseIstc, calculateUint8CrcHash(ptcPackGetUsrData(parseIstc), ptcPackGetDataSize(parseIstc)));
        break;
    }
    default:
    {
        logerror("");
        return 0;
    }
    }
    memcpy(&parseIstc->pkptr[0], parseFixedHead, sizeof(parseFixedHead));
    ptcPackSetVersion(parseIstc, parseIstc->myVersion);
    return ptcPackGetTotalSize(parseIstc);
}

static int ptcPackParseCheckCrc(struct ptcPackOption *parseIstc)
{
    uint8_t tmpcrc;
    switch (parseIstc->myVersion)
    {
    case protocolParseCommonVersion1:
    {
        tmpcrc = calculateUint8CrcHash(ptcPackGetUsrData(parseIstc), ptcPackGetDataSize(parseIstc));
        if (tmpcrc == ptcPackGetCrcU8(parseIstc))
        { // ok
            return 0;
        }
        logerror("%x:%x", tmpcrc, ptcPackGetCrcU8(parseIstc));
        return -1;
    }
    default:
    {
        logerror("");
        break;
    }
    }
    return -1;
}
int ptcPackOptInit(struct ptcPackOption *parseIstc, void *setpack, ptcPackType setPackSize, void *udata, uint8_t setver)
{
    parseIstc->pkptr = setpack;
    parseIstc->pksize = setPackSize;
    parseIstc->userdata = udata;
    parseIstc->myVersion = setver;
    resetParseWork(parseIstc);
    return 0;
}
void ptcPackParseData(struct ptcPackOption *parseIstc, uint8_t indata)
{
    switch (parseIstc->parseState)
    {
    case protocolParseCommonStep_FixedHead:
    {
        if (parseIstc->rcvCount < sizeof(parseFixedHead))
        {
            if (indata == parseFixedHead[parseIstc->rcvCount])
            {

                parseIstc->pkptr[parseIstc->rcvCount++] = indata;
            }
            else
            {
                parseIstc->rcvCount = 0;
                if (indata == parseFixedHead[parseIstc->rcvCount])
                {
                    parseIstc->pkptr[parseIstc->rcvCount++] = indata;
                }
            }
        }
        if (parseIstc->rcvCount >= sizeof(parseFixedHead))
        {
            parseIstc->parseState = protocolParseCommonStep_Version;
        }
        break;
    }
    case protocolParseCommonStep_Version:
    {
        parseIstc->pkptr[parseIstc->rcvCount++] = indata;
        if(!(ptcPackGetVersion(parseIstc) == parseIstc->myVersion))
        {
            logerror("parseVersion:%d!=%d", parseIstc->myVersion, ptcPackGetVersion(parseIstc));
            resetParseWork(parseIstc);
            break;
        }
        parseIstc->needSize = ptcPackGetHeadSize(parseIstc);
        if (!parseIstc->needSize)
        {
            logerror("parseVersion:%d", ptcPackGetHeadSize(parseIstc));
            resetParseWork(parseIstc);
            break;
        }
        parseIstc->parseState = protocolParseCommonStep_AllHead;
        break;
    }
    case protocolParseCommonStep_AllHead:
    {
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            parseIstc->pkptr[parseIstc->rcvCount++] = indata;
        }
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            break;
        }
        parseIstc->needSize = ptcPackGetTotalSize(parseIstc);
        if (!(parseIstc->needSize > ptcPackGetHeadSize(parseIstc) && 
            parseIstc->needSize <= parseIstc->pksize))
        {
            logerror("%u,%u", parseIstc->needSize, parseIstc->pksize);
            resetParseWork(parseIstc);
            break;
        }
        parseIstc->parseState = protocolParseCommonStep_Data;
        break;
    }
    case protocolParseCommonStep_Data:
    {
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            parseIstc->pkptr[parseIstc->rcvCount++] = indata;
        }
        if (parseIstc->rcvCount < parseIstc->needSize)
        {
            break;
        }
        if (ptcPackParseCheckCrc(parseIstc) < 0)
        {
            logerror("");
            resetParseWork(parseIstc);
            break;
        }
        // parse ok!
        ptcPackParseCbk(parseIstc);
    }
    default:
        resetParseWork(parseIstc);
        break;
    }
}
